﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace TVersityDotNet.Providers
{
    /// <summary>
    /// Rest provider for TVersity API.  Makes some assumptions on content types, languages accepted, etc.
    /// </summary>
    public class TVersityRestProvider : IRestProvider
    {
        /// <summary>
        /// Processes a GET request
        /// </summary>
        /// <param name="url">URL of the resource to GET</param>
        /// <returns>Data stream from the response</returns>
        public Stream Get(string url)
        {
            return ProcessRequest(url, "GET", null);
        }

        /// <summary>
        /// Process a POST request
        /// </summary>
        /// <param name="url">URL of the resource being POSTed</param>
        /// <param name="data">Data for the post</param>
        /// <returns>Data stream from the response</returns>
        public Stream Post(string url, byte[] data)
        {
			return ProcessRequest(url, "POST", data);
        }

		/// <summary>
		/// Process a PUT request
		/// </summary>
		/// <param name="url">URL of the resource to which the data is being PUT</param>
		/// <param name="data">Data for the PUT</param>
		/// <returns>Data stream from the response</returns>
        public Stream Put(string url, byte[] data)
        {
			return ProcessRequest(url, "PUT", data);
        }

		/// <summary>
		/// Process a DELETE request
		/// </summary>
		/// <param name="url">Address of the resource to be deleted</param>
		/// <returns>Data stream from the response</returns>
        public Stream Delete(string url)
        {
			return ProcessRequest(url, "DELETE", null);
        }

		/// <summary>
		/// Process a request
		/// </summary>
		/// <param name="url">Address of the request</param>
		/// <param name="method">HTTP method used for the request</param>
		/// <param name="data">Data sent in the request</param>
		/// <returns>Data stream from the response</returns>
        protected Stream ProcessRequest(string url, string method, byte[] data)
        {
             // Create web request
            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
            // Set value for request headers
            httpRequest.Method = method;
            httpRequest.ProtocolVersion = HttpVersion.Version11;
            httpRequest.AllowAutoRedirect = false;
            httpRequest.Accept = "*/*";
            httpRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)";
            httpRequest.Headers.Add("Accept-Language", "en-us");
            httpRequest.KeepAlive = true;
            if (data != null)
            {
                httpRequest.ContentType = "application/x-www-form-urlencoded";
                httpRequest.ContentLength = data.Length;
                using (Stream requestStream = httpRequest.GetRequestStream())
                {
                    requestStream.Write(data, 0, data.Length);
                    requestStream.Close();
                }
            }
            
            Stream returnStream = Stream.Null ;
            try
            {
                returnStream = ((HttpWebResponse)httpRequest.GetResponse()).GetResponseStream();
            }
            catch (WebException)
            {
                returnStream = TVersityRestProvider.GetTversityErrorStream("Invalid URL or error connecting: " + url);
            }
            catch (Exception ex)
            {
                returnStream = TVersityRestProvider.GetTversityErrorStream("Unknown exception while connecting to TVersity server : " + ex.Message);
            }

            return returnStream;
        }

        /// <summary>
        /// Public method used to generate a generic TVersity error stream with a custom message
        /// </summary>
        /// <param name="errorMessage">The error message to include</param>
        /// <returns>A stream representing a custom error</returns>
        public static Stream GetTversityErrorStream(string errorMessage)
        {

            StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + Environment.NewLine);
            //StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            sb.Append(string.Format("<response status=\"failure\" message=\"{0}\" />", errorMessage));

            byte[] byteArray = Encoding.ASCII.GetBytes(sb.ToString());
            return new MemoryStream(byteArray);
        }
    }
}
